package com.the_ring.chapter14.widget;

import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.AspectRatio;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.video.VideoCapture;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;

import com.google.common.util.concurrent.ListenableFuture;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CameraXView extends ViewGroup {

    private Context context;                                        // 上下文对象
    private PreviewView cameraPreview;                              // 预览视图对象
    private CameraSelector cameraSelector;                          // 摄像头选择器
    private Preview preview;                                        // 预览对象
    protected ProcessCameraProvider cameraProvider;                 // 相机提供器
    private ImageCapture imageCapture;                              // 图像捕捉器
    private VideoCapture videoCapture;                              // 视频捕捉器
    private ExecutorService executorService;                        // 线程池对象
    private LifecycleOwner owner;                                   // 生命周期拥有者
    private int cameraType = CameraSelector.LENS_FACING_BACK;       // 摄像头类型
    private int aspectRatio = AspectRatio.RATIO_16_9;               // 宽高比例
    private int flashMode = ImageCapture.FLASH_MODE_AUTO;           // 闪光灯模式
    private String mediaDir;                                        // 媒体保存目录

    public CameraXView(Context context) {
        this(context, null);
    }

    public CameraXView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        cameraPreview = new PreviewView(context);           // 创建一个预览视图
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
        cameraPreview.setLayoutParams(params);
        addView(cameraPreview);                             // 把预览视图添加到界面上
        // 创建一个单线程线程池
        executorService = Executors.newSingleThreadExecutor();
        mediaDir = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

    }

    private int cameraMode = 0;
    Handler mHandler = new Handler(Looper.getMainLooper());

    /**
     * 打开相机
     * @param owner
     * @param cameraMode
     * @param sl
     */
    public void openCamera(LifecycleOwner owner, int cameraMode, OnStopListener sl) {
        this.owner = owner;
        this.cameraMode = cameraMode;
        stopListener = sl;
        mHandler.post(() -> initCamera());      // 初始化相机
    }


    /**
     * 初始化相机
     */
    private void initCamera() {
        ListenableFuture<ProcessCameraProvider> future = ProcessCameraProvider.getInstance(context);
        future.addListener(() -> {
            try {
                cameraProvider = future.get();
                resetCamera();      // 重置相机
            } catch (ExecutionException e) {
                throw new RuntimeException(e);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, ContextCompat.getMainExecutor(context));
    }

    /**
     * 重置相机
     */
    private void resetCamera() {
        int rotation = cameraPreview.getDisplay().getRotation();
        // 构建一个摄像头选择器
        cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(cameraType).build();
        // 构建一个预览对象
        preview = new Preview.Builder()
                .setTargetAspectRatio(aspectRatio)      // 设置宽高比例
                .build();
        // 构建一个图像捕捉器
        imageCapture = new ImageCapture.Builder()
                // 设置捕捉模式
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                .setTargetRotation(rotation)            // 设置旋转角度
                .setTargetAspectRatio(aspectRatio)      // 设置宽高比例
                .setFlashMode(flashMode)                // 设置闪光模式
                .build();
        bindCamera(MODE_PHOTO);                         // 绑定摄像头
        // 设置预览视图的表面提供器
        preview.setSurfaceProvider(cameraPreview.getSurfaceProvider());
    }

    private int MODE_PHOTO = 1;
    /**
     * 绑定摄像头
     * @param captureMode
     */
    private void bindCamera(int captureMode) {
        cameraProvider.unbindAll();             // 重新绑定前要先解绑
        try {
            if (captureMode == MODE_PHOTO) {    // 拍照
                // 把相机选择器、预览视图、图像捕捉器绑定到相机提供器的生命周期
                Camera camera = cameraProvider.bindToLifecycle(
                        owner, cameraSelector, preview, imageCapture);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 关闭相机
     */
    public void closeCamera() {
        cameraProvider.unbindAll();         // 解绑相机提供器
        executorService.shutdown();         // 关闭线程池
    }


    private String photoPath;       // 照片保存路径
    public String getPhotoPath() {
        return photoPath;
    }

    /**
     * 开始拍照
     */
    public void takePicture() {
        photoPath = String.format("%s/%s.jpg", mediaDir, new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        ImageCapture.Metadata metadata = new ImageCapture.Metadata();
        // 构建图像捕捉器的输出选项
        ImageCapture.OutputFileOptions options = new ImageCapture.OutputFileOptions.Builder(new File(photoPath)).setMetadata(metadata).build();
        // 执行拍照动作
        imageCapture.takePicture(options, executorService, new ImageCapture.OnImageSavedCallback() {
            @Override
            public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
                stopListener.onStop("已完成拍摄，照片保存路径为" + photoPath);
            }

            @Override
            public void onError(@NonNull ImageCaptureException exception) {
                stopListener.onStop("拍摄失败，错误信息为：" + exception.getMessage());
            }
        });
    }

    private OnStopListener stopListener;
    public interface OnStopListener {
        void onStop(String msg);
    }
}
